﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace LostLib.Win32
{
	public static class WindowsAPI
	{
		public const int Success = unchecked((int)0x80004005);

		#region Windows
		[DllImport("user32.dll")]
		public static extern bool IsWindow(IntPtr hwnd);

		[DllImport("user32.dll")]
		public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processID);

		[DllImport("user32.dll", SetLastError=true)]
		public static extern IntPtr SetParent(IntPtr child, IntPtr newParent);
		[DllImport("user32.dll", SetLastError=true)]
		public static extern IntPtr GetParent(IntPtr child);

		[DllImport("user32.dll")]
		public static extern bool GetWindowInfo(IntPtr handle, out WindowInfo info);

		[DllImport("user32.dll")]
		public static extern IntPtr GetDesktopWindow( );
		[DllImport("user32.dll")]
		public static extern IntPtr GetForegroundWindow( );

		[DllImport("user32.dll")]
		public static extern bool ShowWindow(IntPtr hwnd, ShowWindowEnum cmdShow);

		[DllImport("user32.dll")]
		public static extern bool SetWindowPos(IntPtr hwnd, IntPtr insertAfter, int x, int y, int w, int h, WindowPosFlags flags);
		[DllImport("user32.dll", EntryPoint="SetWindowLong", SetLastError=true)]
		static extern int _SetWindowLong(IntPtr hwnd, WindowParam parameter, int value);
		[DllImport("user32.dll", EntryPoint="GetWindowLong")]
		static extern int _GetWindowLong(IntPtr hwnd, WindowParam parameter);

		public static int SetWindowLong(IntPtr hwnd, WindowParam parameter, int value)
		{
			SetLastError(0);
			return _SetWindowLong(hwnd, parameter, value);
		}

		public static int GetWindowLong(IntPtr hwnd, WindowParam parameter)
		{
			SetLastError(0);
			return _GetWindowLong(hwnd, parameter);
		}

		public delegate bool EnumChildProc(IntPtr hwnd, IntPtr lParam);
		[DllImport("user32.Dll")]
		public static extern bool EnumChildWindows(IntPtr parentHandle, EnumChildProc callback, IntPtr lParam);
		[DllImport("user32.dll")]
		public static extern int GetWindowText(IntPtr hwnd, StringBuilder outStr, int size);
		[DllImport("user32.dll")]
		public static extern int GetClassName(IntPtr hwnd, StringBuilder outStr, int size);
		#endregion

		#region HotKeys
		[DllImport("user32.dll")]
		public static extern bool RegisterHotKey(IntPtr hwnd, int id, uint modifiers, uint virtualKey);
		[DllImport("user32.dll")]
		public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
		#endregion HoKeys

		#region Atoms
		[DllImport("kernel32.dll")]
		public static extern int GlobalAddAtom(string name);
		[DllImport("kernel32.dll")]
		public static extern int GlobalDeleteAtom(int atom);
		[DllImport("kernel32.dll")]
		static extern uint GetAtomName(Atom atom, StringBuilder buffer, int bufferSize);

		public static string GetAtomName(Atom atom)
		{
			for (int capacity = 1024; capacity < 1024 * 1024; capacity <<= 1)
			{
				var buffer = new StringBuilder(capacity);
				var size = GetAtomName(atom, buffer, buffer.Capacity);
				if (size != 0)
				{
					buffer.Length = (int)size;
					return buffer.ToString( );
				}
			}
			return null;
		}
		#endregion Atoms

		#region Consoles
		[DllImport("kernel32.dll")]
		public static extern IntPtr GetConsoleWindow( );

		[DllImport("kernel32.dll", SetLastError=true)]
		public static extern bool AttachConsole(int processID);

		[DllImport("kernel32.dll", SetLastError=true)]
		public static extern Coord GetConsoleFontSize(IntPtr hConsoleOutput, int font);

		[DllImport("kernel32.dll", SetLastError=true)]
		public static extern bool GetCurrentConsoleFont(IntPtr hOutput, bool bMaximumWindow, out ConsoleFontInfo font);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern IntPtr GetStdHandle(StandardHandle handleType);
		#endregion

		[DllImport("kernel32.dll")]
		public static extern void SetLastError(uint value);

		public static List<IntPtr> GetChildWindows(IntPtr parent)
		{
			List<IntPtr> result = new List<IntPtr>( );
			var listHandle = GCHandle.Alloc(result);
			try
			{
				EnumChildProc childProc = new EnumChildProc(EnumWindow);
				EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
			} finally
			{
				if (listHandle.IsAllocated)
					listHandle.Free( );
			}
			return result;
		}

		private static bool EnumWindow(IntPtr handle, IntPtr pointer)
		{
			GCHandle gch = GCHandle.FromIntPtr(pointer);
			List<IntPtr> list = gch.Target as List<IntPtr>;
			if (list == null)
			{
				throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
			}
			list.Add(handle);
			//  You can modify this to check to see if you want to cancel the operation, then return a null here
			return true;
		}

		public static void HandleWin32Exception( )
		{
			var result = new Win32Exception( );
			if (result.ErrorCode != Success)
			{
				throw result;
			}
		}
	}
}
